<?

namespace core\Db;

use core\Pool\Pool;

class Redis
{

    public static $pool = null;

    public $connect = 'default';

    public static function init()
    {
        $c = config('redis');
        foreach ($c as $k => $v) {
            self::$pool[$k] = new Pool(function () use ($v) {
                $redis = new \Redis();
                $redis->connect($v['host'], (int) $v['port']);
                if ($v['auth']) {
                    $redis->auth($v['auth']);
                }
                $redis->select($v['db']??0);
                return $redis;
            }, 100);
        }
        loger('init');
    }

    public static function  u($connect = null) {
        if (self::$pool == null) {
            self::init();
        }
        $redis          = new self;
        $redis->connect = $connect ?? 'default';
        return $redis;
    }

    public static function __callStatic($method, $args)
    {
        if (self::$pool == null) {
            self::init();
        }

        $redis = self::$pool['default']->get();

        switch ($method) {
            case 'multi':
                $result = call_user_func_array([$redis, $method], $args);
                break;
            default:
                $result = $redis->$method(...$args);
                break;
        }

        self::$pool['default']->put($redis);
        return $result;
    }

    public static function _json($redis, $args)
    {
        // loger([$redis,$args]);
        $method = array_shift($args);
        switch ($method) {
            case 'set':
                if ($vv=$args[2]??null) {
                    if (is_array($vv)) {
                        $vv = json_encode($vv);
                    } 
                    $result = $redis->rawCommand('JSON.SET', $args[0],'.'.$args[1],$vv);
                } else{
                    $result = $redis->rawCommand('JSON.SET', $args[0],'.',json_encode($args[1]));
                }
                // [$key,$value] = $args;
                // $result = $redis->rawCommand('JSON.SET', $key,'.',json_encode($value));
                break;
            case 'append':
                [$key,$k,$v] = $args;
                $result = $redis->rawCommand('JSON.SET', $key,'.'.$k,$v);
                break;
            default:
                $result = null;
                break;
        }
        return $result;
    }

    public static function _index($redis,$args)
    {
        [$index,$table,$schema] = $args;

        $arr=[$index,'ON','JSON','PREFIX',1,$table,'SCHEMA'];

        foreach ($schema as $k => $v) {
            $arr=array_merge($arr,['$.'.$k,'AS',$k,...$v]);
        }

        // loger('FT.CREATE' .implode(' ',$arr));
        $result = $redis->rawCommand('FT.CREATE', ...$arr);

        return $result;
    }

    public static function query($index)
    {
       
        return new Query($index);
    }

    public function __call($method, $args)
    {
        $redis = self::$pool[$this->connect]->get();
        switch ($method) {
            case 'multi':
                $result = call_user_func_array([$redis, $method], $args);
                break;
            case 'json':
                $result = self::_json($redis,$args);
                break;
            case 'index':
                $result = self::_index($redis,$args);
                break;
            // case 'query':
                // $result = 
            default:
                $result = $redis->$method(...$args);
                break;
        }
        self::$pool[$this->connect]->put($redis);
        return $result;
    }

    function __destruct() {
        // print "Destroying " . __CLASS__ . "\n";
    }

}


/**
 * 
 */
class Query 
{
    public $index;

    

    public $Q=[];

    function __construct($index)
    {
        $this->index = $index;
        
    }

    public function page($page,$limit)
    {
        $page = $page < 2 ? 0: $page;
        $this->Q['limit']=['LIMIT',$page*$limit,$limit];

        return $this;
    }

    public function limit($s,$e)
    {
        $this->Q['limit']=['LIMIT',$s,$e];
        return $this;
    }

    public function field($value='')
    {
        $t = explode(',',$value);
        $this->Q['field']=[count($t),$t];
        return $this;
    }

    public function orderby($k='',$s='')
    {
        $this->Q['orderby']=['SORTBY',$k,$s];
        return $this;
    }

    public function where($w)
    {
        $this->Q['where']=$w;
        return $this;
    }

    public function result()
    {
        $query[]=$this->index;
        $query[]=$this->Q['where']??'*';
        if ($this->Q['limit']??null) {
            $query = array_merge($query,$this->Q['limit']);
        } else {
            // $query = array_merge($query,['LIMIT',0,10]);
        }

        if ($this->Q['orderby']??null) {
            $query = array_merge($query,$this->Q['orderby']);
        }

        if ($this->Q['field']??null) {
            $query = array_merge($query,['RETURN',$this->Q['field'][0],...$this->Q['field'][1]]);
        }
        // loger($query); 

      
        $tmp=Redis::rawCommand('FT.SEARCH',...$query);
       

        $result['total']=array_shift($tmp);
        // loger($tmp);
        if ($this->Q['field']??null) {
            foreach ($tmp as $k => $v) {
                if ($k%2==1) {
                    for ($i=0; $i < $this->Q['field'][0]*2; $i+=2) { 
                        $field[$v[$i]]=$v[$i+1];
                    }
                    $result['list'][]=$field;
                }
            }
        } else {
            foreach ($tmp as $k => $v) {
                if ($k%2==1) {
                    $result['list'][]=json_decode(end($v),true);
                }
            }
        }

        return $result ?? [];
    }
}